home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Gold Medal Software 3
/
Gold Medal Software - Volume 3 (Gold Medal) (1994).iso
/
utils1
/
hdnfojt.arj
/
HDINFO.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-23
|
6KB
|
185 lines
#include <dos.h>
#include <string.h>
#include <conio.h>
#include <mem.h>
#include "hdinfo.h"
unsigned secbuf[2][256];
unsigned char biosbuf[64];
int drive0;
int drive1;
long thcap;
unsigned char temp;
void readsect( int drive)
// This function reads the drive parameter directly into
// 256 byte buffer. A 256 byte sector must be read, despite
// the fact that only the first few bytes are actually useful
// (see ideinfo struct)
{
int i;
outp(HDC_SDH, 0xA0 + (drive<<4)); // Setup task file parameter
outp(HDC_COMMAND, HDC_COMMAND_READPAR); // Issue read parameters command
while(inp(HDC_STATUS) & HDC_STATUS_BUSY); // Poll DRQ
for (i=0; i<256; ++i) // Read Sector
secbuf[drive][i] = inpw(HDC_DATA);
};
void interpret_info( int drive)
// now interpret the data read by the previous function
{
int i, k;
char c;
char s[80];
struct ideinfo *id = (struct ideinfo *)secbuf[drive];
thcap = ((long)id->fixcyls * id->heads);
id->capacity = ((double)thcap * id->sectors) / 2048;
id->bioscapacity = ((double)id->biosheads * id->biossecs * id->bioscyls)/2048;
// ascii strings read from the drive are read as INTS with the
// opposite high/low byte ordering than the PC.
// Therefore we must swap alternate bytes to return
// to normal intel 80x86 ordering.
// fix serial string
for(i=0; i < 10; ++i)
{
c = id->serial[i*2];
id->serial[i*2] = id->serial[i*2+1];
id->serial[i*2+1] = c;
};
// fix firmware revision string
for(i=0; i < 4; ++i)
{
c = id->firmware[i*2];
id->firmware[i*2] = id->firmware[i*2+1];
id->firmware[i*2+1] = c;
};
// fix model information string
for(i=0; i < 20; ++i)
{
c = id->model[i*2];
id->model[i*2] = id->model[(i*2)+1];
id->model[i*2+1] = c;
};
// for Seagate and Western Digital drives, expand the model
// data so it is clear who the manufacturer is. There are
// probably umpteen more drives where this is necessary, but
// these are the ones I come across on a day to day basis.
if( memicmp( id->model, "WDC", 3) == 0)
{
strcpy( s, "Western Digital -");
strcat( s, (char *)id->model+3);
strncpy( id->model, s, 40);
};
if( memicmp( id->model, "st", 2) == 0)
{
strcpy( s, "Seagate - ST");
strcat( s, (char *)id->model+2);
strncpy( id->model, s, 40);
};
// if controller type is 4 or above it is unknown
if( id->contype > 4) id->contype = 4;
// convert the dblword flag into an integer value indicating
// the number of bits (16 or 32) that can be transfered in a single
// read/write via the hard drive controller
++id->dblword <<= 4;
id->bestcyls = id->fixcyls;
id->bestheads = id->heads;
id->bestsecs = id->sectors;
// if the number of physical cylinders is greater than 1024
// then the drive internally remaps its configuration to suit
// the PC bios (which only allows a maximum of 1024 cylinders).
// We therefore need to calculate BIOS settings which are legal
// (as far as the BIOS is concerned) but which still give us 100%
// use of the physical drive space. All drives that I have
// tested seem to hold the sector/cylinders constant and modify
// the number of heads on the drive.
// BIOS uses allows the following maximum values:-
// Cylinders = 1024 : 10 bits
// Heads = 256 : 8 bits
// Sectors/Cylinder = 64 : 5 bits
if (id->fixcyls >= 1024)
{
for ( i = id->heads; i < 256 ; i++)
if ( ((thcap % i) == 0) && ((thcap / i) < 1024) )
{
id->bestcyls = thcap / i;
id->bestheads = i;
id->bestsecs = id->sectors;
break;
};
// if no factors can be found and we still have over 1024 cylinders
// then truncate the excess - some Maxtor drive do this (which means
// that you can never use all the space on those models - on a PC)
if (id->bestcyls >= 1024) id->bestcyls = 1024;
};
};
int check_drive( int drive)
// Check to see if the drive exists or not.
// Returns true if the drive is there.
{
outp(HDC_SDH, 0xA0 + (drive<<4)); // Setup task file parameter
if (inp(HDC_STATUS) == 0xFF) return(0); // if status = 0xff then no disk
while(inp(HDC_STATUS) & HDC_STATUS_BUSY); // Poll DRQ and wait if necc.
outp(HDC_CYLLOW, 0xAA); // test even bits in port
if (inp(HDC_CYLLOW) != 0xAA) return(0); // if change then no disk
outp(HDC_CYLLOW, 0x55); // test odd bits in port
if (inp(HDC_CYLLOW) != 0x55) return(0); // if change then no disk
if ((inp(HDC_STATUS) & 0x40) == 0) return(0); // check status changes
return( 1);
};
void readbios( int drive)
// get the drive information as it is stored for BIOS use
{
union REGS regs;
struct ideinfo *id = (struct ideinfo *)secbuf[drive];
// use BIOS interrupt 0x13 function 8 to get drive details
regs.h.ah = 0x08;
regs.h.dl = drive+0x80; // bit 7 set for hard drives
int86(0x13, ®s, ®s);
if (regs.h.dl < (drive+1)) return;
id->biosheads = regs.h.dh + 1;
id->biossecs = regs.h.cl & 0x3f;
// for some reason the BIOS int 0x13 funct. 8 does not return
// the same number as cylinders as the CMOS settings for the
// drive (it is always 1 or 2 short). However reading the
// number of cylinder directly from the drive parameter table
// gives the correct result (where does BIOS go wrong?).
if (drive == 0) id->bioscyls = **(unsigned int far * far *)(0x41 * 4);
if (drive == 1) id->bioscyls = **(unsigned int far * far *)(0x46 * 4);
};
void readdrives( void)
// This is the main function which calls all the rest.
{
outp(HDC_FIXED, 0); // Disable drive interrupts
drive0 = check_drive( DRIVE_0); // check that drive 0 exists
drive1 = check_drive( DRIVE_1); // check that drive 1 exists
if (drive0) readsect( DRIVE_0); // if exists read data for drive 0
if (drive1) readsect( DRIVE_1); // if exists read data for drive 1
outp(HDC_FIXED, HDC_FIXED_IRQ); // Re-enable disk interrupts
if (drive0) readbios( DRIVE_0); // Get Bios data for drive 0
if (drive1) readbios( DRIVE_1); // Get Bios data for drive 1
if (drive0) interpret_info( DRIVE_0); // Calculate capacity etc
if (drive1) interpret_info( DRIVE_1); // calculate stats for drive 1
};